package org.chen.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.paypal.core.PayPalHttpClient;
import com.paypal.http.HttpResponse;
import com.paypal.orders.Order;
import com.paypal.orders.OrdersGetRequest;
import com.paypal.payments.CapturesRefundRequest;
import com.paypal.payments.Refund;
import com.paypal.payments.RefundRequest;
import lombok.extern.slf4j.Slf4j;
import org.chen.common.constants.Constants;
import org.chen.common.exception.FlyingException;
import org.chen.common.model.SystemAdmin;
import org.chen.common.model.travel.StoreTravelOrder;
import org.chen.common.user.User;
import org.chen.common.utils.DateUtil;
import org.chen.common.utils.RedisUtil;
import org.chen.enu.CancelResult;
import org.chen.service.*;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static net.sf.jsqlparser.parser.feature.Feature.execute;

@Service
@Slf4j
public class StoreTravelOrderTaskServiceImpl implements StoreTravelOrderTaskService {
    //日志
    private static final Logger logger = LoggerFactory.getLogger(StoreTravelOrderTaskServiceImpl.class);

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StoreTravelOrderService storeTravelOrderService;

    @Autowired
    private StoreOrderStatusService storeOrderStatusService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private UserService userService;

    @Autowired
    private AlertService alertService;

    @Resource
    private PayPalHttpClient payPalHttpClient;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 用户取消订单
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, FlyingException.class})
    public Boolean cancelByUser(StoreTravelOrder storeOrder) {
        String lockKey = "order_cancel_by_user_lock:" + storeOrder.getId();
        RLock lock = redissonClient.getLock(lockKey);
        try{
            if (lock.tryLock(5,TimeUnit.SECONDS)){
                /*
                 * 1、修改订单状态 （用户操作的时候已处理）
                 * 2、使PayPal支付链接失效
                 * 3、写订单日志
                 * */
                //使PayPal支付链接失效(等PayPal自己过期)
                // 获取PayPal的捕获ID
                if (storeOrder.getPaid()){
                    // 获取PayPal的捕获ID
                    String captureId = getCaptureIdFromOrder(storeOrder.getPayId());

                    // 创建退款请求
                    CapturesRefundRequest refundRequest = new CapturesRefundRequest(captureId);
                    RefundRequest refundRequestBody = new RefundRequest();
                    com.paypal.payments.Money money = new com.paypal.payments.Money().currencyCode("THB").value(storeOrder.getPayPrice().toString());
                    refundRequestBody.amount(money);
                    refundRequest.requestBody(refundRequestBody);

                    // 执行退款
                    HttpResponse<com.paypal.payments.Refund> response = payPalHttpClient.execute(refundRequest);
                    com.paypal.payments.Refund refund = response.result();

                    if ("COMPLETED".equals(refund.status())) {
                        // 更新订单状态
                        storeOrder.setRefundStatus(2); // 已退款
                        storeOrder.setRefundPrice(storeOrder.getPayPrice());
                        storeOrder.setRefundReasonTime(DateUtil.nowDateTime());
                        boolean result = storeTravelOrderService.updateById(storeOrder);
                        if (result){
                            publishOrderRefundTask(storeOrder);
                            // 记录订单日志
                            storeOrderStatusService.createTravelLog(storeOrder.getId(), Constants.ORDER_LOG_REFUND_SUCCESS, "PayPal退款成功");
                            storeOrderStatusService.createTravelLog(storeOrder.getId(), Constants.ORDER_LOG_REFUND_APPLY, "用户申请退款原因：用户自主取消");
                        }
                    }
                }
                //写订单日志
                return storeOrderStatusService.createTravelLog(storeOrder.getId(), "cancel_order", "取消订单");
            }
        } catch (InterruptedException | IOException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Boolean.FALSE;
    }

    private void publishOrderRefundTask(StoreTravelOrder storeOrder) {
        try {
            kafkaTemplate.send("order-cancel_refund-task", objectMapper.writeValueAsString(storeOrder));
        } catch (JsonProcessingException e) {
            log.error("Failed to publish order refund task", e);
        }
    }

    private String getCaptureIdFromOrder(String payPalOrderId) throws IOException {
        OrdersGetRequest request = new OrdersGetRequest(payPalOrderId);
        Order payPalOrder = payPalHttpClient.execute(request).result();
        return payPalOrder.purchaseUnits().get(0).payments().captures().get(0).id();
    }

    /**
     * 完成订单
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, FlyingException.class})
    public Boolean complete(StoreTravelOrder storeOrder) {
        /*
         * 1、修改订单状态 （用户操作的时候已处理）
         * 2、写订单日志
         * */
        String lockKey = "order_complete_success_lock:" + storeOrder.getId();
        RLock lock = redissonClient.getLock(lockKey);
        try{
            if (lock.tryLock(5, TimeUnit.SECONDS)){
                storeOrderStatusService.createTravelLog(storeOrder.getId(), "check_order_over", "用户完成订单");
                if (!storeOrder.getIsRemind()){
                    pushMessageOrder(storeOrder);
                }
                return true;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 订单退款通知处理
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, FlyingException.class})
    public Boolean refundOrder(StoreTravelOrder storeOrder) {
        /*
          1、写订单日志
          2、发送通知
         */
        // 获取用户对象

        User user = userService.getById(storeOrder.getUid());
        if (ObjectUtil.isNull(user)) {
            logger.error("订单退款处理，对应的用户不存在,storeOrder===>" + storeOrder);
            return Boolean.FALSE;
        }

        //写订单日志
        Boolean execute = storeOrderStatusService.saveRefund(storeOrder.getId(), storeOrder.getRefundPrice(), "退款成功");

        if (Boolean.TRUE.equals(execute)){
            pushMessageOrderSuccessRefund(storeOrder);
            publishOrderRefundEvent(storeOrder);
        }

        return execute;
    }

    /**
     * 系统记录今日退款金额*
     * @param storeOrder (旅游)订单
     */
    private void publishOrderRefundEvent(StoreTravelOrder storeOrder) {
        try {
            String orderJson = objectMapper.writeValueAsString(storeOrder);
            kafkaTemplate.send("order-refund", orderJson);
        } catch (JsonProcessingException e) {
            logger.error("Failed to publish order refund event", e);
        }
    }

    /**
     * 超时未支付系统自动取消
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, FlyingException.class})
    public CancelResult autoCancel(StoreTravelOrder storeOrder) {
        String lockKey = "order_auto_cancel_lock:" + storeOrder.getId();
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 1️⃣ 获取分布式锁（3秒等待，自动释放）
            if (!lock.tryLock(3, TimeUnit.SECONDS)) {
                logger.warn("获取订单取消锁失败，订单ID：{}", storeOrder.getId());
                return CancelResult.SYSTEM_ERROR;
            }

            // 2️⃣ 重新查询订单（防止数据过期）
            StoreTravelOrder latestOrder = storeTravelOrderService.getById(storeOrder.getId());
            if (latestOrder == null) {
                logger.error("订单不存在，订单ID：{}", storeOrder.getId());
                return CancelResult.DOES_NOT_EXIST_CANCELLED; // 订单不存在，移除队列
            }

            // 3️⃣ 快速校验
            if (latestOrder.getStatus() == 3 || latestOrder.getPaid() ||
                    latestOrder.getIsDel() || latestOrder.getIsSystemDel()) {
                logger.info("订单已取消，订单号：{}", latestOrder.getOrderId());
                return CancelResult.ALREADY_CANCELLED;
            }

            // 如果有支付单号，检查 PayPal 状态
            if (StrUtil.isNotBlank(latestOrder.getPayId())) {
                try {
                    String paymentStatus = checkPayPalOrderStatus(latestOrder.getPayId());
                    if ("APPROVED".equals(paymentStatus)) {
                        logger.info("订单支付中，跳过取消，订单号：{}",
                                latestOrder.getOrderId());
                        return CancelResult.PAYMENT_IN_PROGRESS;
                    }

                    if ("COMPLETED".equals(paymentStatus)) {
                        logger.info("订单已支付，跳过取消，订单号：{}",
                                latestOrder.getOrderId());
                        return CancelResult.ALREADY_PAID;
                    }
                } catch (Exception e) {
                    logger.error("检查PayPal状态失败，为安全起见不取消订单", e);
                    return CancelResult.SYSTEM_ERROR;
                }
            }

            // 4️⃣ 获取配置的取消时间 检查是否超时（加缓冲时间）
            String cancelStr = systemConfigService.getValueByKey("order_cancel_time");
            String bufferStr = systemConfigService.getValueByKey("order_cancel_buffer");
            int hours = parseHours(cancelStr);
            int buffer = parseHours(bufferStr);

            // 5️⃣ 计算订单过期时间
            DateTime cancelTime = cn.hutool.core.date.DateUtil.offset(
                    latestOrder.getCreateTime(),
                    DateField.HOUR_OF_DAY,
                    hours + buffer
            );

            // 6️⃣ 检查是否超时
            long between = cn.hutool.core.date.DateUtil.between(
                    cancelTime,
                    cn.hutool.core.date.DateUtil.date(),
                    DateUnit.SECOND,
                    false
            );

            if (between < 0) {
                logger.debug("订单未到取消时间，订单号：{}，剩余{}秒",
                        latestOrder.getOrderId(), Math.abs(between));
                return CancelResult.NOT_YET_EXPIRED; // 未到期，放回队列
            }

            // 7️⃣ 执行取消操作（使用乐观锁更新订单）
            UpdateWrapper<StoreTravelOrder> wrapper = new UpdateWrapper<>();
            wrapper.eq("id", latestOrder.getId())
                    .eq("version", latestOrder.getVersion())
                    .eq("paid", false)
                    .ne("status", 3);

            StoreTravelOrder update = new StoreTravelOrder();
            update.setIsDel(true);
            update.setIsSystemDel(true);
            update.setStatus(3);
            update.setVersion(latestOrder.getVersion() + 1);

            boolean updated = storeTravelOrderService.update(update, wrapper);
            if (!updated) {
                logger.warn("订单取消失败（版本冲突或状态已变更），订单号：{}",
                        latestOrder.getOrderId());
                return CancelResult.SYSTEM_ERROR; // 更新失败，放回队列
            }

            // 8️⃣ 记录订单日志
            storeOrderStatusService.createTravelLog(
                    latestOrder.getId(),
                    "cancel",
                    String.format("到期未支付系统自动取消（超时%d小时）", hours)
            );

            logger.info("订单自动取消成功，订单号：{}", latestOrder.getOrderId());
            return CancelResult.SUCCESS;

        } catch (Exception e) {
            logger.error("订单取消异常，订单ID：{}", storeOrder.getId(), e);
            return CancelResult.SYSTEM_ERROR;
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 检查 PayPal 订单状态
     * @param payPalOrderId PayPal 订单ID
     * @return 订单状态（CREATED/APPROVED/COMPLETED等）
     */
    private String checkPayPalOrderStatus(String payPalOrderId) throws IOException {
        OrdersGetRequest request = new OrdersGetRequest(payPalOrderId);
        HttpResponse<Order> response = payPalHttpClient.execute(request);
        return response.result().status();
    }

    /**
     * 解析取消时间配置
     */
    private int parseHours(String cancelStr) {
        if (StrUtil.isBlank(cancelStr)) {
            logger.warn("未配置 order_cancel_time，使用默认值3小时");
            return 3;
        }

        try {
            int hours = Integer.parseInt(cancelStr);
            if (hours <= 0 || hours > 72) {
                logger.warn("订单取消时间配置超出范围：{}，使用默认值3小时", cancelStr);
                return 3;
            }
            return hours;
        } catch (NumberFormatException e) {
            logger.error("订单取消时间配置格式错误：{}，使用默认值3小时", cancelStr, e);
            return 3;
        }
    }

    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class, FlyingException.class})
    public Boolean paySuccess(StoreTravelOrder storeOrder) {
        if (ObjectUtil.isNull(storeOrder)) {
            throw new FlyingException(StrUtil.format("订单task处理，未找到订单，id={}", storeOrder.getOrderId()));
        }

        if (storeOrder.getPaid()){
            // 日志
            Boolean execute = storeOrderStatusService.createTravelLog(storeOrder.getId(), "user_pay_success", Constants.ORDER_STATUS_STR_TAKE);
            // 发送用户使用通知用户
            if (Boolean.TRUE.equals(execute)) {
                // 发送消息通知
                pushMessageOrderSuccessPay(storeOrder);
            }
            return execute;
        }
        return Boolean.FALSE;
    }

    @Override
    public Boolean generatePayMenteLinkSuccess(StoreTravelOrder storeOrder) {
        try{
            if (storeOrder.getIsRemind() == null || !storeOrder.getIsRemind()){
                storeOrder.setIsRemind(true);
                storeTravelOrderService.updateById(storeOrder);
                pushMessageGeneratePayMenteLink(storeOrder);
                logger.info("发送生成链接通知邮件成功，收件人：{}，订单号：{}", storeOrder.getEmail(), storeOrder.getOrderId());
            }
            storeOrderStatusService.createTravelLog(storeOrder.getId(), "generate_a_payment_link", "用户生成支付链接");
            return true;
        }catch (Exception e){
            return false;
        }
    }

    /**
     * 发送消息通知
     * 邮件
     */
    private void pushMessageOrder(StoreTravelOrder storeOrder) {
        // 发送邮件通知
        if (storeOrder.getEmail() != null && !storeOrder.getEmail().isEmpty()) {
            try {
                String emailSubject = "订单使用通知";
                String emailContent = String.format(
                        "尊敬的用户：<br><br>" +
                                "您的订单 %s 已成功使用。<br>" +
                                "订单状态：已完成<br>" +
                                "使用时间：%s<br>" +
                                "详情请登录您的账户查看。<br><br>" +
                                "感谢您的使用。期待下次与你相见。<br>" +
                                "此致<br>" +
                                "客户服务团队",
                        storeOrder.getOrderId(),
                        DateUtil.nowDateTimeStr()
                );

                alertService.sendHtmlEmail(storeOrder.getEmail(), emailSubject, emailContent);
                logger.info("发送订单使用通知邮件成功，收件人：{}，订单号：{}", storeOrder.getEmail(), storeOrder.getOrderId());
            } catch (Exception e) {
                // 记录日志，但不中断流程
                logger.error("发送订单使用通知邮件失败，收件人：{}，订单号：{}，错误信息：{}", storeOrder.getEmail(), storeOrder.getOrderId(), e.getMessage());
            }
        }
    }

    private void pushMessageOrderSuccessPay(StoreTravelOrder storeOrder) {
        // 发送邮件通知
        if (storeOrder.getEmail() != null && !storeOrder.getEmail().isEmpty()) {
            try {
                String emailSubject = "订单支付成功通知";
                String emailContent = String.format(
                        "尊敬的用户：<br><br>" +
                                "您的订单 %s 已成功支付。<br>" +
                                "订单状态：已支付<br>" +
                                "支付单号：%s<br>" +
                                "支付时间：%s<br>" +
                                "支付金额：%s<br>" +
                                "详情请登录您的账户查看。<br><br>" +
                                "感谢您的使用。<br>" +
                                "此致<br>" +
                                "客户服务团队",
                        storeOrder.getOrderId(),
                        storeOrder.getPayId(),
                        storeOrder.getPayTime(),
                        storeOrder.getPayPrice()
                        );

                alertService.sendHtmlEmail(storeOrder.getEmail(), emailSubject, emailContent);
                logger.info("发送订单支付成功通知邮件成功，收件人：{}，订单号：{}", storeOrder.getEmail(), storeOrder.getOrderId());
            } catch (Exception e) {
                // 记录日志，但不中断流程
                logger.error("发送订单支付成功通知邮件失败，收件人：{}，订单号：{}，错误信息：{}", storeOrder.getEmail(), storeOrder.getOrderId(), e.getMessage());
            }
        }
    }

    private void pushMessageOrderSuccessRefund(StoreTravelOrder storeOrder) {
        // 发送邮件通知
        if (storeOrder.getEmail() != null && !storeOrder.getEmail().isEmpty()) {
            try {
                String emailSubject = "订单退款成功通知";
                String emailContent = String.format(
                        "尊敬的用户：<br><br>" +
                                "您的订单 %s 已成功退款。<br>" +
                                "订单状态：已退款<br>" +
                                "退款时间：%s<br>" +
                                "退款金额：%s<br>" +
                                "详情请登录您的账户查看。<br><br>" +
                                "感谢您的使用。<br>" +
                                "此致<br>" +
                                "客户服务团队",
                        storeOrder.getOrderId(),
                        DateUtil.nowDateTimeStr(),
                        storeOrder.getPayPrice()
                );

                alertService.sendHtmlEmail(storeOrder.getEmail(), emailSubject, emailContent);
                logger.info("发送订单退款成功通知邮件成功，收件人：{}，订单号：{}", storeOrder.getEmail(), storeOrder.getOrderId());
            } catch (Exception e) {
                // 记录日志，但不中断流程
                logger.error("发送订单退款成功通知邮件失败，收件人：{}，订单号：{}，错误信息：{}", storeOrder.getEmail(), storeOrder.getOrderId(), e.getMessage());
            }
        }
    }

    private void pushMessageGeneratePayMenteLink(StoreTravelOrder storeOrder) {
        // 发送邮件通知
        if (storeOrder.getEmail() != null && !storeOrder.getEmail().isEmpty()) {
            try {
                List<String> configKeys = new ArrayList<>();
                configKeys.add("order_cancel_time");
                List<String> configValues = systemConfigService.getValuesByKes(configKeys);
                Date timeSpace;
                timeSpace = DateUtil.addSecond(storeOrder.getCreateTime(),Double.valueOf(configValues.get(0)).intValue() * 3600);
                String emailSubject = "支付链接生成通知";
                String emailContent = String.format(
                        "尊敬的用户：<br><br>" +
                                "您的订单 %s 的支付链接已生成。<br>" +
                                "支付单号: %s<br>"+
                                "支付链接：%s<br>" +
                                "请在 %s 规定时间内完成支付。<br>" +
                                "详情请登录您的账户查看。<br><br>" +
                                "感谢您的使用。<br>" +
                                "此致<br>" +
                                "客户服务团队",
                        storeOrder.getOrderId(),
                        storeOrder.getPayId(),
                        storeOrder.getPayUrl(),
                        DateUtil.dateToStr(timeSpace, Constants.DATE_FORMAT)
                );

                alertService.sendHtmlEmail(storeOrder.getEmail(), emailSubject, emailContent);
                logger.info("发送支付链接生成通知邮件成功，收件人：{}，订单号：{}", storeOrder.getEmail(), storeOrder.getOrderId());
            } catch (Exception e) {
                // 记录日志，但不中断流程
                logger.error("发送支付链接生成通知邮件失败，收件人：{}，订单号：{}，错误信息：{}", storeOrder.getEmail(), storeOrder.getOrderId(), e.getMessage());
            }
        }
    }
}
